#ifndef __NIGHTCONFIG_H__
#define __NIGHTCONFIG_H__

#include "NightMemory.h"
#include "NightSingleton.h"
#include "NightDelegate.h"
#include "NightXML.h"
#include "NightINI.h"

#include "map"
#include "string"


namespace NE
{

	class ConfigBase : public AllocatedObject
	{
	public:
		ConfigBase(const std::string& name)
			: mConfigName(name) { }
		const std::string& getConfigName(void) const
		{
			return mConfigName;
		}
		virtual void setDefault(void) = 0;
	private:
		const std::string mConfigName;
	};


	template <typename ConfigType>
	class ConfigEvents
	{
    public:
		void apply(void)
		{
			if (!eventConfigModified.invoking())
				eventConfigModified.invoke(*static_cast<ConfigType*>(this));
		}
	public:
		MultiEvent1<void, const ConfigType&> eventConfigModified;
	};


	class ConfigXml : public ConfigBase
	{
	public:
		ConfigXml(const std::string& name)
			: ConfigBase(name) { }
		virtual void _load(const XmlNode<>* node) = 0;
		virtual void _save(XmlNode<>* node) = 0;
	};


	class ConfigIni : public ConfigBase
	{
	public:
		ConfigIni(const std::string& name)
			: ConfigBase(name) { }
		virtual void _load(const IniSection<>* section) = 0;
		virtual void _save(IniSection<>* section) = 0;
	};


	class ConfigManager : public Singleton<ConfigManager>
	{
	public:
		ConfigManager(void);
		virtual ~ConfigManager(void);

		void addConfig(const std::string& group_name, ConfigXml* config_xml);
		void addConfig(const std::string& group_name, ConfigIni* config_ini);

		ConfigBase* getConfig(const std::string& group_name, const std::string& config_name);

		virtual void destroyAllConfigs(void);

		bool loadXmlFile(const std::string& group_name, const std::string& file_path);
		bool loadIniFile(const std::string& group_name, const std::string& file_path);

		void loadDefault(const std::string& group_name);

		bool saveXmlFile(const std::string& group_name, const std::string& file_path);
		bool saveIniFile(const std::string& group_name, const std::string& file_path);

	protected:
		struct XmlConfigPack
		{
			char* file_buffer;
			XmlDocument<>* document;
			std::map<std::string, ConfigXml*> config_map;
			typedef std::pair<ConfigXml*, XmlNode<>*> IndexItem;
			std::vector<IndexItem> config_list;
			XmlConfigPack(void) : file_buffer(0), document(0) { }
		};
		std::map<std::string, XmlConfigPack> mXmlConfigPacks;

		struct IniConfigPack
		{
			char* file_buffer;
			IniDocument<>* document;
			std::map<std::string, ConfigIni*> config_map;
			typedef std::pair<ConfigIni*, IniSection<>*> IndexItem;
			std::vector<IndexItem> config_list;
			IniConfigPack(void) : file_buffer(0), document(0) { }
		};
		std::map<std::string, IniConfigPack> mIniConfigPacks;

	private:
	};

}


#endif
